package com.lookme.lmtool.cracker.filter.edge;

import com.jhlabs.image.EdgeFilter;
import com.jhlabs.image.GrayscaleFilter;
import com.lookme.lmtool.cracker.CrackerConstants;
import com.lookme.lmtool.cracker.annotation.FilterAnnotation;
import com.lookme.lmtool.cracker.annotation.ParamAnnotation;
import com.lookme.lmtool.cracker.filter.AbstractFilter;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Arrays;

@FilterAnnotation(groupName = CrackerConstants.FILTER_GROUP_NAME_EDGE,name="边缘检测2",filterClass = EdgeFilter.class)
public class FilterEdge2 extends AbstractFilter {
    @XStreamAsAttribute
    @ParamAnnotation(name = "算法类型", desc = "算法类型",inputType = ParamAnnotation.InputType.Radio,width = 70,options = {"Roberts","0","Sobel","1","Prewitt","2","Krisch","3","Laplace","4"})
    int type=0;


    //设置算子的卷积核
    //Roberts算子卷积核
    transient double[][] robertsX = {{1, 0}, {0, -1}};
    transient double[][] robertsY = {{0, 1}, {-1, 0}};
    //Sobel算子卷积核
    transient double[][] sobelX = {{1, 0, -1}, {2, 0, -2}, {1, 0, -1}};
    transient double[][] sobelY = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}};
    //Prewitt算子卷积核
    transient double[][] prewittX = {{-1, 0, 1}, {-1, 0, 1}, {-1, 0, 1}};
    transient double[][] prewittY = {{1, 1, 1}, {0, 0, 0}, {-1, -1, -1}};
    //Krisch算子卷积核
    transient double[][] krischN = {{5, 5, 5}, {-3, 0, -3}, {-3, -3, -3}};
    transient double[][] krischNE = {{-3, 5, 5}, {-3, 0, 5}, {-3, -3, -3}};
    transient double[][] krischE = {{-3, -3, 5}, {-3, 0, 5}, {-3, -3, 5}};
    transient double[][] krischSE = {{-3, -3, -3}, {-3, 0, 5}, {-3, 5, 5}};
    transient double[][] krischS = {{-3, -3, -3}, {-3, 0, -3}, {5, 5, 5}};
    transient double[][] krischSW = {{-3, -3, -3}, {5, 0, -3}, {5, 5, -3}};
    transient double[][] krischW = {{5, -3, -3}, {5, 0, -3}, {5, -3, -3}};
    transient double[][] krischNW = {{5, 5, -3}, {5, 0, -3}, {-3, -3, -3}};
    //Laplace算子卷积核
    transient double[][] laplace = {{1, 1, 1}, {1, -8, 1}, {1, 1, 1}};

    @Override
    public BufferedImage filter(BufferedImage src, BufferedImage dst) {
        int width=src.getWidth();
        int height=src.getHeight();
        int size = 3;

        if(type==0){
            size = 2;
        }else{
            size=3;
        }
        //首先将图片灰度化
        dst=new GrayscaleFilter().filter(src,dst);


        //下面代码中width代表图片宽度，height代表图片高度，gray为图片的灰度数组，存储的是每个像素点的灰度值
        if (type==0||type==1||type==2) {
            double[][] operatorX=(type==0?robertsX:(type==1?sobelX:prewittX));
            double[][] operatorY=(type==0?robertsY:(type==1?sobelY:prewittY));
            for (int x = 0; x < width - size + 1; x++) {
                for (int y = 0; y < height - size + 1; y++) {
                    //设置x,y方向的结果变量，一定要在循环内初始化，因为每次循环都要清零重新加
                    int tempX = 0;
                    int tempY = 0;
                    //对size*size区域进行卷积操作
                    for (int i = 0; i < size; i++) {
                        for (int j = 0; j < size; j++) {
                            tempX += dst.getRGB(x + i,y + j) * operatorX[i][j];
                            tempY += dst.getRGB(x + i,y + j) * operatorY[i][j];
                        }
                    }
                    //求梯度值
                    int result = (int) Math.sqrt(tempX * tempX + tempY * tempY);
                    //设置阈值
                    int RMax = 200;
                    //根据阈值设置黑白度
                    if (result > RMax) {
                        result = 255;
                    }
                    if (result <= RMax) {
                        result = 0;
                    }
                    //设置颜色来描点
                    Color color = new Color(result, result, result);
                    dst.setRGB(x + size / 2, y + size / 2,color.getRGB());
                }
            }
        } else if (type==3) {
            for (int x = 0; x < width - size + 1; x++) {
                for (int y = 0; y < height - size + 1; y++) {
                    //设置一个数组存储八个方向的值,按顺时针方向从北极开始
                    int[] temp = {0, 0, 0, 0, 0, 0, 0, 0};
                    //对size*size区域进行卷积操作
                    for (int i = 0; i < size; i++) {
                        for (int j = 0; j < size; j++) {
                            temp[0] += dst.getRGB(x + i,y + j) * krischN[i][j];
                            temp[1] += dst.getRGB(x + i,y + j) * krischNE[i][j];
                            temp[2] += dst.getRGB(x + i,y + j) * krischE[i][j];
                            temp[3] += dst.getRGB(x + i,y + j) * krischSE[i][j];
                            temp[4] += dst.getRGB(x + i,y + j) * krischS[i][j];
                            temp[5] += dst.getRGB(x + i,y + j) * krischSW[i][j];
                            temp[6] += dst.getRGB(x + i,y + j) * krischW[i][j];
                            temp[7] += dst.getRGB(x + i,y + j) * krischNW[i][j];
                        }
                    }
                    //找出八个方向的最大值（代码为数组列表求最大值）
                    int result = Arrays.stream(temp).max().getAsInt();
                    //若是求得结果超出灰度值的0-255范围，将其设成最大值或最小值
                    if (result > 255) {
                        result = 255;
                    }
                    if (result < 0) {
                        result = 0;
                    }
                    //画图
                    Color color = new Color(result, result, result);
                    dst.setRGB(x + size / 2, y + size / 2,color.getRGB());
                }
            }
        } else if (type==4) {
            for (int x = 0; x < width - size + 1; x++) {
                for (int y = 0; y < height - size + 1; y++) {
                    int result = 0;
                    //对size*size区域进行卷积操作
                    for (int i = 0; i < size; i++) {
                        for (int j = 0; j < size; j++) {
                            result += dst.getRGB(x + i,y + j) * laplace[i][j];
                        }
                    }
                    //设置阈值
                    int LMax = 150;
                    //根据阈值设置黑白度
                    if (result > LMax) {
                        result = 255;
                    }
                    if (result < LMax) {
                        result = 0;
                    }
                    //画图
                    Color color = new Color(result, result, result);
                    dst.setRGB(x + size / 2, y + size / 2,color.getRGB());
                }
            }
        }
        return dst;
    }
}
